/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../xos/head.h"
#include "../os/head.h"
#include "crt_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static crt_impl::ITEM_DATA xos_item_data;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    crt_impl::crt_impl()
    {
    }

    crt_impl::~crt_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int crt_impl::get_xos_item_data( ITEM_DATA *& item_ptr )
    {
        int ret = 0;
        xos_item_data.set_container( mgr::container() );
        item_ptr = &xos_item_data;
        return ret;
    }

    int crt_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int crt_impl::term()
    {
        int nRet = 0;
        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    const void * crt_impl::mem_find( const void * lpMainMem, size_t tMainLen, const void * lpSubMem, size_t tSubLen )
    {
        const char * lpszMainMem = (const char *)lpMainMem;
        const char * lpszSubMem = (const char *)lpSubMem;
        size_t nStep = tMainLen - tSubLen + 1;
        const char * lpszRet = 0;

        for( size_t i = 0; i < nStep; ++i )
        {
            size_t ret = memcmp( lpszMainMem + i, lpszSubMem, tSubLen );
            if( 0 == ret )
            {
                lpszRet = lpszMainMem + i;
                break;
            }
        }

        return lpszRet;
    }

    int crt_impl::memmove( void * lpDst, const void * lpSrc, size_t tSize )
    {
        const char * lpszSrc = (const char *)lpSrc;
        char * lpszDst = (char *)lpDst;
        int ret = 0;
        ::memmove( lpszDst, lpszSrc, tSize );
        return ret;
    }

    int crt_impl::memcpy( void * lpDst, const void * lpSrc, size_t tSize )
    {
        int ret = 0;
        ::memcpy( lpDst, lpSrc, tSize );
        return ret;
    }

    int crt_impl::memset( void * lpDst, int nValue, size_t tSize )
    {
        int ret = 0;
        ::memset( lpDst, nValue, tSize );
        return ret;
    }

    const char * crt_impl::strrstr( const char * lpszStr, const char * lpszSubStr, bool bCaseSensitive )
    {
        const char * lpStr = 0;

        int nSrcLen = ( int )::strlen( lpszSubStr );
        int nDstLen = ( int )::strlen( lpszStr );
        int nStep = nDstLen - nSrcLen;

        if( nStep < 0 )
        {
            return lpStr;
        }

        if( bCaseSensitive )
        {
            const char * p = 0;

            for( int i = nStep; i >= 0; --i )
            {
                p = StrStrA( lpszStr + i, lpszSubStr );

                if( p )
                {
                    lpStr = p;
                    break;
                }
            }
        }
        else
        {
            lpStr = StrRStrIA( lpszStr, 0, lpszSubStr );
        }

        return lpStr;
    }

    const char * crt_impl::strstr( const char * lpszStr, const char * lpszSubStr, bool bCaseSensitive )
    {
        const char * lpStr = 0;

        if( bCaseSensitive )
        {
            lpStr = StrStrA( lpszStr, lpszSubStr );
        }
        else
        {
            lpStr = StrStrIA( lpszStr, lpszSubStr );
        }

        return lpStr;
    }

    char * crt_impl::strrstr( char * lpszStr, const char * lpszSubStr, bool bCaseSensitive )
    {
        return (char *)strrstr( (const char *)lpszStr, lpszSubStr, bCaseSensitive );
    }

    char * crt_impl::strstr( char * lpszStr, const char * lpszSubStr, bool bCaseSensitive )
    {
        return (char *)strstr( (const char *)lpszStr, lpszSubStr, bCaseSensitive );
    }

    const char * crt_impl::strrchr( const char * lpszStr, char c )
    {
        return ::strrchr( lpszStr, c );
    }

    const char * crt_impl::strchr( const char * lpszStr, char c )
    {
        return ::strchr( lpszStr, c );
    }

    char * crt_impl::strrchr( char * lpszStr, char c )
    {
        return ::strrchr( lpszStr, c );
    }

    char * crt_impl::strchr( char * lpszStr, char c )
    {
        return ::strchr( lpszStr, c );
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int crt_impl::vsnprintf( xos_box::i_string * pStr, const char * format, va_list argptr )
    {
        int ret = 0;
        xos_box::i_big_buf * pBuf = mgr::container()->box()->big_buf();
        char * pB = pBuf->get_data( 0, 0, 0, 0 );
        int nSize = pBuf->get_buf_size( 0 );
        ret = vsnprintf( pB, nSize, format, argptr );
        if( ret > 0 )
        {
            pStr->set( pB, ret );
        }
        xos_stl::release_interface( pBuf );
        return ret;
    }

    int XOS_API_CDECL crt_impl::sprintf( xos_box::i_string * pStr, const char * lpszFormat, ... )
    {
        int ret = 0;
        {
            va_list  va;
            va_start( va, lpszFormat );
            ret = vsnprintf( pStr, lpszFormat, va );
            va_end( va );
        }
        return ret;
    }

    int crt_impl::strftime( xos_box::i_string * pStr, const char * fmt, const struct tm * tm )
    {
        int ret = 0;
        xos_box::i_big_buf * pBuf = mgr::container()->box()->big_buf();
        char * pB = pBuf->get_data( 0, 0, 0, 0 );
        int nSize = pBuf->get_buf_size( 0 );
        {
            int nLen = (int)::strftime(pB, nSize, fmt, tm);
            if( ( nLen > 0 ) && ( nLen < nSize ) )
            {
                pB[nLen] = 0;
            }
            pStr->set( pB, nLen );
        }
        xos_stl::release_interface( pBuf );
        return ret;
    }

    int crt_impl::gets( xos_box::i_string * pStr )
    {
        int ret = 0;
        xos_box::i_big_buf * pBuf = mgr::container()->box()->big_buf();
        char * pB = pBuf->get_data( 0, 0, 0, 0 );
        int nSize = pBuf->get_buf_size( 0 );
        {
            this->gets( pB, nSize - 1 );
            pStr->set( pB );
        }
        xos_stl::release_interface( pBuf );
        return ret;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int crt_impl::vsnprintf( char * lpszBuf, int nBufSize, const char * format, va_list argptr )
    {
        return ::vsnprintf_s( lpszBuf, nBufSize, -1, format, argptr );
    }

    int XOS_API_CDECL crt_impl::sprintf( char * buf, int nBufSize, const char * lpszFormat, ... )
    {
        int nRet = 0;
        {
            va_list  va;
            va_start( va, lpszFormat );
            nRet = ::vsnprintf_s( buf, nBufSize, _TRUNCATE, lpszFormat, va );
            va_end( va );
        }
        return nRet;
    }

    const char * crt_impl::strptime( const char * buf, const char * fmt, struct tm * tm )
    {
        return ms_strptime( buf, fmt, tm );
    }

    int crt_impl::gets( char * lpszBuf, int nBufSize )
    {
        int nRet = 0;
        fgets( lpszBuf, nBufSize - 1, stdin );
        return nRet;
    }

    double crt_impl::atof( const char * lpszStr )
    {
        return ::atof( lpszStr );
    }

    int64_t crt_impl::atoi64( const char * lpszStr )
    {
        LONGLONG llData = 0;
        StrToInt64ExA( lpszStr, 0, &llData );
        return llData;
    }

    int crt_impl::atoi( const char * lpszStr )
    {
        return StrToIntA( lpszStr );
    }

    int crt_impl::atol( const char * lpszStr )
    {
        return ::atol( lpszStr );
    }

    int crt_impl::uppercase( const char * lpszSrc, char * lpszDst )
    {
        int nRet = 0;

        while( char c = *lpszSrc++ )
        {
            *lpszDst++ = toupper( c );
        }

        *lpszDst = 0;

        return nRet;
    }

    int crt_impl::lowercase( const char * lpszSrc, char * lpszDst )
    {
        int nRet = 0;

        while( char c = *lpszSrc++ )
        {
            *lpszDst++ = tolower( c );
        }

        *lpszDst = 0;

        return nRet;
    }

    int crt_impl::toupper( char c )
    {
        int nRet = ::toupper( c );
        return nRet;
    }

    int crt_impl::tolower( char c )
    {
        int nRet = ::tolower( c );
        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    // wchar_t
    wchar_t * crt_impl::strncpy( wchar_t * lpszDst, size_t tBufLen, const wchar_t * lpszSrc, size_t tLen )
    {
        assert( tBufLen > tLen );
        ::wcsncpy_s( lpszDst, tBufLen, lpszSrc, tLen );
        return lpszDst;
    }

    wchar_t * crt_impl::strcpy( wchar_t * lpszDst, size_t tBufLen, const wchar_t * lpszSrc )
    {
        ::wcscpy_s( lpszDst, tBufLen, lpszSrc );
        return lpszDst;
    }

    wchar_t * crt_impl::strcat( wchar_t * lpszDst, size_t tBufLen, const wchar_t * lpszSrc )
    {
        ::wcscat_s( lpszDst, tBufLen, lpszSrc );
        return lpszDst;
    }

    int crt_impl::strlen( const wchar_t * lpszStr )
    {
        return lstrlenW( lpszStr );
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    char * crt_impl::strncpy( char * lpszDst, size_t tBufSize, const char * lpszSrc, size_t tLen )
    {
        ::strncpy_s( lpszDst, tBufSize, lpszSrc, tLen );
        return lpszDst;
    }

    char * crt_impl::strcpy( char * lpszDst, size_t tBufSize, const char * lpszSrc )
    {
        ::strcpy_s( lpszDst, tBufSize, lpszSrc );
        return lpszDst;
    }

    char * crt_impl::strcat( char * lpszDst, size_t tBufSize, const char * lpszSrc )
    {
        ::strcat_s( lpszDst, tBufSize, lpszSrc );
        return lpszDst;
    }

    int crt_impl::strlen( const char * lpszStr )
    {
        return lstrlenA( lpszStr );
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int crt_impl::stricmp( const char * lpszStr1, const char * lpszStr2 )
    {
        return lstrcmpiA( lpszStr1, lpszStr2 );
    }

    int crt_impl::strcmp( const char * lpszStr1, const char * lpszStr2 )
    {
        return lstrcmpA( lpszStr1, lpszStr2 );
    }

    // 
    // if uSeed is 0, sys will add seed
    // 
    int crt_impl::srand( uint32_t uSeed )
    {
        int nRet = 0;

        if( 0 == uSeed )
        {
            uSeed = (uint32_t)time( 0 );
        }

        ::srand( uSeed );

        return nRet;
    }

    int crt_impl::rand( int nMax )
    {
        int nRet = 0;
        nRet = ::rand() % nMax;
        return nRet;
    }
} // xos
